package org.beynet.docs.auth;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.TextOutputCallback;
import javax.security.auth.callback.UnsupportedCallbackException;

public class GSyncCallbackHandler implements CallbackHandler {

    public void handle(Callback[] callbacks)
    throws IOException, UnsupportedCallbackException {

        for (Callback callback : callbacks) {
            if (callback instanceof TextOutputCallback) {

                // display the message according to the specified type
                TextOutputCallback toc = (TextOutputCallback)callback;
                switch (toc.getMessageType()) {
                case TextOutputCallback.INFORMATION:
                    System.out.println(toc.getMessage());
                    break;
                case TextOutputCallback.ERROR:
                    System.out.println("ERROR: " + toc.getMessage());
                    break;
                case TextOutputCallback.WARNING:
                    System.out.println("WARNING: " + toc.getMessage());
                    break;
                default:
                    throw new IOException("Unsupported message type: " +
                            toc.getMessageType());
                }

            } else if (callback instanceof NameCallback) {

                // prompt the user for a username
                NameCallback nc = (NameCallback)callback;

                System.err.print(nc.getPrompt());
                System.err.flush();
                nc.setName((new BufferedReader
                        (new InputStreamReader(System.in))).readLine());

            } else if (callback instanceof PasswordCallback) {

                // prompt the user for sensitive information
                PasswordCallback pc = (PasswordCallback)callback;
                System.err.print(pc.getPrompt());
                System.err.flush();
                pc.setPassword(readPassword(System.in));
                
            } else {
                throw new UnsupportedCallbackException(callback, "Unable to handle this callback");
            }
        }
    }

    protected void clearBuffer(char[] buffer) {
        for (int i=0;i<buffer.length;i++) buffer[i]=0;
    }
    
    protected char[] checkSize(char[] buffer,int read) {
        if (read==buffer.length) {
            char[] tmp=new char[buffer.length*2];
            System.arraycopy(buffer, 0, tmp, 0, buffer.length);
            clearBuffer(buffer);
            buffer=tmp;
        }
        return(buffer);
    }
    

    protected char[] readPassword(InputStream is) throws IOException {
        char[] buffer = new char[1];
        int read = 0 ;
        int next = -1 ;
        do {
            char c ;
            if (next!=-1) {
                c = (char)next ;
                next=-1;
            }
            else {
                c = (char) is.read();
            }
            if (c==-1 || c=='\n') {
                break;
            }
            if (c=='\r') {
                next = is.read();
                if (next==-1 || next=='\n') {
                    break;
                }
            }
            buffer=checkSize(buffer, read);
            buffer[read++] = c;

        } while(true);
        char[] result = new char[read];
        if (read==0) return(null);
        System.arraycopy(buffer, 0, result, 0, read);
        clearBuffer(buffer);
        return(result);
    }

}